﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Media;
using TeBigScreenWpf.WordCloud.Geometry;

namespace TeBigScreenWpf.WordCloud
{
    public class WpfGraphicEngine : IGraphicEngine, IDisposable
    {
        private readonly DrawingContext m_dc;

        private readonly double m_MinWordWeight;
        private readonly double m_MaxWordWeight;
        private Typeface m_LastTypeface;

        public Color[] Palette { get; private set; }
        public double MinFontSize { get; set; }
        public double MaxFontSize { get; set; }

        public WpfGraphicEngine(DrawingContext dc, Typeface typeface, Color[] palette, float minFontSize, float maxFontSize, int minWordWeight, int maxWordWeight)
        {
            m_MinWordWeight = minWordWeight;
            m_MaxWordWeight = maxWordWeight;
            m_dc = dc;
            m_LastTypeface = typeface;
            Palette = palette;
            MinFontSize = minFontSize;
            MaxFontSize = maxFontSize;
        }

        public Size Measure(string text, int weight)
        {
            var fontsize = GetFontSize(weight);

            FormattedText ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                new Typeface(m_LastTypeface.FontFamily, m_LastTypeface.Style, GetFontWeight(weight), m_LastTypeface.Stretch), 
                GetFontSize(weight), new SolidColorBrush(Colors.Blue));

            return new Size(ft.Width, ft.Height);
        }

        private void DrawText(string text, int weight, Point point, Color color)
        {
            var fontsize = GetFontSize(weight);

            FormattedText ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                new Typeface(m_LastTypeface.FontFamily, m_LastTypeface.Style,
                GetFontWeight(weight),
                m_LastTypeface.Stretch), GetFontSize(weight), new SolidColorBrush(color));

            m_dc.DrawText(ft, point);
        }

        public void Draw(LayoutItem layoutItem)
        {
            Color color = GetPresudoRandomColorFromPalette(layoutItem);

            Point point = new Point((int)layoutItem.Rectangle.X, (int)layoutItem.Rectangle.Y);

            DrawText(layoutItem.Word.Text, layoutItem.Word.Occurrences, point, color);
        }

        public void DrawEmphasized(LayoutItem layoutItem)
        {
            double fontsize = GetFontSize(layoutItem.Word.Occurrences);

            Color color = GetPresudoRandomColorFromPalette(layoutItem);

            Point point = new Point((int)layoutItem.Rectangle.X, (int)layoutItem.Rectangle.Y);

            DrawText(layoutItem.Word.Text, layoutItem.Word.Occurrences, point, Colors.LightGray);

            int offset = (int)(5 * fontsize / MaxFontSize) + 1;

            point.Offset(-offset, -offset);

            DrawText(layoutItem.Word.Text, layoutItem.Word.Occurrences, point, Colors.LightGray);
        }

        private double GetFontSize(double weight)
        {
            double weight_diff = Math.Max(1, m_MaxWordWeight - m_MinWordWeight);
            double font_diff = Math.Max(1, MaxFontSize - MinFontSize);


            return (weight - m_MinWordWeight) / weight_diff * font_diff + MinFontSize;
        }

        public FontWeight GetFontWeight(double weight)
        {
            return FontWeight.FromOpenTypeWeight(Math.Min(999, (int)weight));
        }

        private Color GetPresudoRandomColorFromPalette(LayoutItem layoutItem)
        {
            Color color = Palette[layoutItem.Word.Occurrences * layoutItem.Word.Text.Length % Palette.Length];
            return color;
        }

        public void Dispose()
        {
        }
    }
}